package ModelLayer;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

public class Lease implements Serializable {

	private static final long serialVersionUID = 1L;
	private static int lastid;
	private int id;
	private Customer customer;
	private Status status;
	private boolean pickup;
	private Employee employee;
	private double finalPrice;
	private long startDate;
	private long endDate;
	private long returnDate;
	private String dAddress;
	private ArrayList<LeaseItemUnit> leaseItemUnits;
	private static final double MAXDISCOUNT = 0.2;

	public Lease(int customerId, int employeeId, long startDate, long endDate)
			throws RealException {

		this.startDate = startDate;
		this.endDate = endDate;
		setStatus(Status.BorrowedLease);
		setId(getNewId());
		finalPrice = 0;
		customer = CustomerRecords.getInstance().getCustomer(customerId);
		employee = EmployeeRecords.getInstance().getEmployee(employeeId);
		leaseItemUnits = new ArrayList<LeaseItemUnit>();

	}

	// calculate final price
	public double calculateFinalPrice() {
		double totalPrice = 0;
		for (LeaseItemUnit LeaseItemUnit : leaseItemUnits) {
			totalPrice += LeaseItemUnit.getLeaseItem().getPrice()
					* getDuration();
		}
		return totalPrice;
	}

	// return lease period in days
	public int getDuration() {
		long dateDifference = getEndDate() - getStartDate();
		int duration = (int) (dateDifference / (24 * 60 * 60 * 1000));
		return duration;
	}

	// add a lease item unit to lease
	public void addLeaseItemUnit(int leaseItemid, int serialNo)
			throws RealException {
		LeaseItemUnit leaseItemUnit = getLeaseItemUnit(leaseItemid, serialNo);
		if (leaseItemUnit.getStatus() == Status.Available) {
			leaseItemUnits.add(leaseItemUnit);
			leaseItemUnit.setStatus(Status.Borrowed);
			setFinalPrice(calculateFinalPrice());
		} else if (leaseItemUnit.getStatus() == Status.Borrowed) {
			throw new RealException("Lease item is borrowed");
		}
	}

	// remove a lease item unit to lease
	public void removeLeaseItemUnit(int leaseItemId, int serialNo)
			throws RealException {
		LeaseItemUnit leaseItemUnit = getLeaseItemUnit(leaseItemId, serialNo);
		if (leaseItemUnit.getStatus() == Status.Borrowed) {
			leaseItemUnit.setStatus(Status.Available);
		}
		leaseItemUnits.remove(leaseItemUnit);
	}

	// return a lease item unit
	public LeaseItemUnit getLeaseItemUnit(int id, int serialNo)
			throws RealException {
		LeaseItemRecords leaseItemRecords = LeaseItemRecords.getInstance();
		LeaseItemUnit leaseItemUnit = leaseItemRecords.getLeaseItemUnit(id,
				serialNo);
		if (leaseItemUnit != null) {
			return leaseItemUnit;
		} else {
			throw new RealException("Lease item is not found");
		}
	}
	// print all lease item unit information for a lease
	public String listAllLeaseItemUnits() {
		String description = "";
		for (LeaseItemUnit leaseItemUnit : leaseItemUnits) {
			description += leaseItemUnit.getLeaseItem().getDetails();
			description += leaseItemUnit.toString();
		}
		description += "\nTotal price: " + getFinalPrice();
		return description;
	}

	// convert date from long to string type
	public String convertDate(long date) {
		String orderDate = new SimpleDateFormat("dd/MM/yyyy").format(new Date(
				date));
		return orderDate;
	}

	// return current day
	public long getCurrentDate() {
		Calendar cal = Calendar.getInstance();
		java.util.Date utilDate = cal.getTime();
		return utilDate.getTime();
	}

	// print information about a lease
	public String toString() {
		String description;
		description = "\n\nId: " + id + "\nCustomer: " + customer.getName()
				+ "\nEmployee: " + employee.getName() + "\nStatus: "
				+ getStatus().toString() + "\nPayment Term: "
				+ customer.getGroup().getPaymentTerm() + "\nStart Date: "
				+ convertDate(startDate) + "\nEnd Date: "
				+ convertDate(endDate);
		if (status == Status.ReturnedLease
				|| status == Status.ReturnedLeaseExpired) {
			description += "\nReturn Date: " + convertDate(returnDate);
		}
		description += "\n";
		if (leaseItemUnits.size() != 0) {
			description += listAllLeaseItemUnits();
		} else {
			description += "\n No lease item unit is added";
		}
		return description;
	}

	public void returnLease(long returnDate) throws RealException {

		if (getStatus() == Status.BorrowedLease) {
			if (returnDate <= endDate) {
				setStatus(Status.ReturnedLease);
			} else {
				setStatus(Status.ReturnedLeaseExpired);
			}
			returnLeaseItemUnits();
			this.returnDate = returnDate;
		} else {
			throw new RealException("Lease status is not 'BorrowedLease'.");
		}
	}

	// return lease item unit for a lease
	public void returnLeaseItemUnits() {
		for (LeaseItemUnit leaseItemUnit : leaseItemUnits) {
			leaseItemUnit.setStatus(Status.Available);
		}
	}

	// get new distinct id
	public static int getNewId() {
		return ++lastid;
	}

	public static void setLastId(int lastId) {
		lastid = lastId;
	}

	public static int getLastId() {
		return lastid;
	}

	public int getId() {
		return id;
	}

	public void setStartDate(long startDate) {
		this.startDate = startDate;
	}

	public long getStartDate() {
		return startDate;
	}

	public void setId(int id) {
		this.id = id;
	}

	public void setPickup(boolean pickup) {
		this.pickup = pickup;
	}

	public boolean getPickup() {
		return pickup;
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public ArrayList<LeaseItemUnit> getLeaseItemUnits() {
		return leaseItemUnits;
	}

	public void setLeaseItemUnits(ArrayList<LeaseItemUnit> leaseItemUnits) {
		this.leaseItemUnits = leaseItemUnits;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public Status getStatus() {
		return status;
	}

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	public double getFinalPrice() {
		return finalPrice;
	}

	public void setFinalPrice(double finalPrice) {
		this.finalPrice = finalPrice;
	}

	public static double getMaxdiscount() {
		return MAXDISCOUNT;
	}

	public void setEndDate(long endDate) {
		this.endDate = endDate;
	}
	
	public void setReturnDate(long returnDate) {
		this.returnDate = returnDate;
	}
	
	public long getReturnDate() {
		return returnDate;
	}

	public long getEndDate() {
		return endDate;
	}

	public String getdAddress() {
		return dAddress;
	}

	public void setdAddress(String dAddress) {
		this.dAddress = dAddress;
	}
	
	public String getStartDateFormatted()
	{
		return convertDate(startDate);
	}
	
	public String getEndDateFormatted()
	{
		return convertDate(endDate);
	}
	
	public String getReturnDateFormatted()
	{
		return convertDate(returnDate);
	}

}
